package czh.cocoa.ui;

import czh.cocoa.foundation.NSArray;
import czh.cocoa.foundation.NSMutableArray;
import czh.cocoa.foundation.NSObject;
import czh.cocoa.foundation.NSRange;
import czh.cocoa.graphics.CGRect;
import czh.cocoa.graphics.CGSize;
import czh.cocoa.ui.impl.UINavigationBar;
import czh.cocoa.ui.impl.UINavigationBarDelegate;
import czh.cocoa.ui.impl.UINavigationItem;
import czh.cocoa.ui.impl.UIToolbar;

public class UINavigationController extends UIViewController implements UINavigationBarDelegate {
	
	private NSMutableArray mViewControllers;
	
	private boolean mNavigationBarHidden;
	
	private UINavigationBar mNavigationBar;
	
	private boolean mToolbarHidden;
	
	private UIToolbar mToolbar;
	
	public UINavigationController() {
		mViewControllers = new NSMutableArray(3);
		mToolbarHidden = true;
		mNavigationBar = new UINavigationBar();
		mToolbar = new UIToolbar();
	}
	
	public UINavigationController(UIViewController root) {
		this();
		NSArray controllers = NSArray.arrayWithObjects(root);
		setViewControllers(controllers);
	}
	
	public void viewDidLoad() {
		UIView view = view();
		CGRect bounds = view.bounds();
		
		if (!mNavigationBarHidden) { 
			CGRect frame = mNavigationBar.frame();
			frame.size.width = bounds.size.width;
			mNavigationBar.setFrame(frame);
			mNavigationBar.setDelegate(this);
			NSArray items = getNavigationItems(mViewControllers);
			mNavigationBar.setItems(items);
			view.addSubview(mNavigationBar); 
		}
		if (!mToolbarHidden) {
			CGRect frame = mToolbar.frame();
			frame.origin.y = bounds.size.height - frame.size.height;
			frame.size.width = bounds.size.width;
			mToolbar.setFrame(frame);
			mToolbar.setAutoresizingMask(UIView.UIViewAutoresizingFlexibleTopMargin);
			NSArray items = getToolbarItems(mViewControllers);
			mToolbar.setItems(items);
			view.addSubview(mToolbar);
		}
		UIViewController ctrl = topViewController();
		if (ctrl != null) {
			CGRect frame = getViewControllerFrame();
			ctrl.view().setFrame(frame);
			view.addSubview(ctrl.view());
		}
	}
	
	public void setNavigationBarHidden(boolean hidden) {
		mNavigationBarHidden = hidden;
	}
	
	public boolean navigationBarHidden() {
		return mNavigationBarHidden;
	}
	
	public UINavigationBar navigationBar() {
		return mNavigationBar;
	}
	
	public void setToolBarHidden(boolean hidden) {
		mToolbarHidden = hidden;
	}
	
	public boolean toolBarHidden() {
		return mToolbarHidden;
	}
	
	public UIToolbar toolbar() {
		return mToolbar;
	}
	
	public NSArray viewControllers() {
		return new NSArray(mViewControllers);
	}
	
	public void setViewControllers(NSArray controllers) {
		UIViewController ctrl0 = topViewController();
		if (ctrl0 != null && ctrl0.isViewLoaded()) {
			ctrl0.view().removeFromSuperview();
		}
		
		final NSMutableArray stack = mViewControllers;
		
		for (NSObject o : stack) {
			UIViewController ctrl = (UIViewController) o;
			ctrl.setNavigationController(null); 
		}
		
		stack.removeAllObjects();
		stack.addObjectsFromArray(controllers);
		
		for (NSObject o : controllers) {
			UIViewController ctrl = (UIViewController) o;
			ctrl.setNavigationController(this); 
		}
		
		if (!mNavigationBarHidden) {
			NSArray items = getNavigationItems(controllers);
			mNavigationBar.setItems(items);
		}
		
		if (!mToolbarHidden) {
			NSArray items = getToolbarItems(controllers);
			mToolbar.setItems(items);
		}
		
		UIViewController ctrl = topViewController();
		if (ctrl != null && isViewLoaded()) {
			CGRect frame = getViewControllerFrame();
			ctrl.view().setFrame(frame);
			view().addSubview(ctrl.view());
		}
	}
	
	private NSArray getNavigationItems(NSArray controllers) {
		int count = controllers.count();
		NSMutableArray items = new NSMutableArray(count);
		for (int i = 0; i < count; i++) {
			UIViewController ctrl = (UIViewController) controllers.objectAtIndex(i);
			items.addObject(ctrl.navigationItem());
		}
		return items;
	}
	
	private NSArray getToolbarItems(NSArray controllers) {
		UIViewController ctrl = (UIViewController) controllers.lastObject();
		if (ctrl != null) {
			return ctrl.toolbarItems();
		}
		return null;
	}
	
//	private void addControllerView(UIViewController ctrl, boolean animated) {
//		UIView view = view();
//		CGRect bounds = view.bounds();
//		if (!mNavigationBarHidden) {
//			float navibar_h = mNavigationBar.frame().size.height;
//			bounds.origin.y = navibar_h;
//			bounds.size.height -= navibar_h;
//		}
//		ctrl.view().setFrame(bounds);
//		view.addSubview(ctrl.view());
//	}
	
	private CGRect getViewControllerFrame() {
		CGRect bounds = view().bounds();
		if (!mNavigationBarHidden) {
			float navibar_h = mNavigationBar.frame().size.height;
			bounds.origin.y = navibar_h;
			bounds.size.height -= navibar_h;
		}
		if (!mToolbarHidden) {
			bounds.size.height -= mToolbar.frame().size.height;
		}
		return bounds;
	}
	
//	private void removeTopControllerView(boolean animated) {
//		UIViewController top_ctrl = topViewController();
//		if (top_ctrl != null && top_ctrl.isViewLoaded()) {
//			top_ctrl.view().removeFromSuperview();
//		}
//	}
	
	public UIViewController topViewController() {
		return (UIViewController) mViewControllers.lastObject();
	}
	
	public void pushViewControllerAnimated(UIViewController ctrl, boolean animated) {
		if (!mNavigationBarHidden) {
			mNavigationBar.pushNavigationItemAnimated(ctrl.navigationItem(), animated); 
		}
		
		if (!mToolbarHidden) {
			mToolbar.setItems(ctrl.toolbarItems());
		}
		
		UIViewController ctrl0 = topViewController();
		UIAnimationBlock anim0 = null;
		UIAnimationBlock.Completion completion0 = null;
		
		if (ctrl0 != null) {
			if (ctrl0.isViewLoaded()) { 
				final UIView view0 = ctrl0.view();
				final CGRect frame0 = view0.frame();
				if (animated) {
					anim0 = new UIAnimationBlock() {
						@Override
						public void run() {
							frame0.origin.x = -frame0.size.width;
							view0.setFrame(frame0); 
						}
					};
					completion0 = new UIAnimationBlock.Completion() {
						@Override
						public void run(boolean finished) {
							frame0.origin.x = 0;
							view0.setFrame(frame0);
							view0.removeFromSuperview();
						}
					};
				} else {
					view0.removeFromSuperview();
				}
			}
			ctrl0.setNavigationController(null); 
		}
		
		mViewControllers.addObject(ctrl);
		
		final UIView view = ctrl.view();
		final CGRect frame = getViewControllerFrame();
		
		if (animated) {
			frame.origin.x = frame.size.width;
			view.setFrame(frame); 
			view().addSubview(view);
			
			final UIAnimationBlock _anim0 = anim0;
			final UIAnimationBlock.Completion _completion0 = completion0; 
			
			UIView.animateWithDurationAnimationsCompletion(0.3, new UIAnimationBlock() {
				@Override
				public void run() {
					if (_anim0 != null) {
						_anim0.run();
					}
					frame.origin.x = 0;
					view.setFrame(frame); 
				}
			}, new UIAnimationBlock.Completion() {
				@Override
				public void run(boolean finished) {
					if (_completion0 != null) {
						_completion0.run(finished);
					}
				}
			});
		} else {
			view.setFrame(frame); 
			view().addSubview(view);
		}
		
		ctrl.setNavigationController(this);
		
	}
	
	public UIViewController popViewControllerAnimated(boolean animated) {
		int count = mViewControllers.count();
		if (count > 1) {
			if (!mNavigationBarHidden) {
				mNavigationBar.popNavigationItemAnimated(animated);
			}
			
			UIViewController ctrl0 = (UIViewController) mViewControllers.objectAtIndex(count - 1);
			UIAnimationBlock anim0 = null;
			UIAnimationBlock.Completion completion0 = null;
			if (ctrl0.isViewLoaded()) {
				final UIView view0 = ctrl0.view();
				final CGRect frame0 = view0.frame();
				if (animated) {
					anim0 = new UIAnimationBlock() {
						@Override
						public void run() {
							frame0.origin.x = frame0.size.width;
							view0.setFrame(frame0); 
						}
					};
					completion0 = new UIAnimationBlock.Completion() {
						@Override
						public void run(boolean finished) {
							frame0.origin.x = 0;
							view0.setFrame(frame0);
							view0.removeFromSuperview();
						}
					};
				} else {
					view0.removeFromSuperview();
				}
			}
			
			ctrl0.setNavigationController(null);
			
			UIViewController ctrl = (UIViewController) mViewControllers.objectAtIndex(count - 2);
			
			final UIView view = ctrl.view();
			final CGRect frame = getViewControllerFrame();
			
			if (animated) {
				frame.origin.x = -frame.size.width;
				view.setFrame(frame); 
				view().addSubview(view);
				
				final UIAnimationBlock _anim0 = anim0;
				final UIAnimationBlock.Completion _completion0 = completion0;
				
				UIView.animateWithDurationAnimationsCompletion(0.3, new UIAnimationBlock() {
					@Override
					public void run() {
						if (_anim0 != null) {
							_anim0.run();
						}
						frame.origin.x = 0;
						view.setFrame(frame); 
					}
				}, new UIAnimationBlock.Completion() {
					@Override
					public void run(boolean finished) {
						if (_completion0 != null) {
							_completion0.run(finished);
						}
					}
				});
			} else {
				view.setFrame(frame); 
				view().addSubview(view);
			}
			
			if (!mToolbarHidden) {
				mToolbar.setItems(ctrl.toolbarItems());
			}
			
			mViewControllers.removeObject(ctrl0);
			
			return ctrl0;
		}
		return null;
	}
	
	public NSArray popToViewControllerAnimated(UIViewController ctrl, boolean animated) {
		int index = mViewControllers.indexOfObject(ctrl);
		if (index != NSNotFound) {
			UIViewController ctrl0 = topViewController();
			if (ctrl0 != ctrl) {
				int count = mViewControllers.count();
				if (!mNavigationBarHidden) { 
					for (int i = 0; i < count - index - 2; i++) {
						mNavigationBar.popNavigationItemAnimated(false);
					}
					mNavigationBar.popNavigationItemAnimated(true);
				}
				
				UIAnimationBlock anim0 = null;
				UIAnimationBlock.Completion completion0 = null;
				
				if (ctrl0.isViewLoaded()) {
					final UIView view0 = ctrl0.view();
					final CGRect frame0 = view0.frame();
					if (animated) {
						anim0 = new UIAnimationBlock() {
							@Override
							public void run() {
								frame0.origin.x = frame0.size.width;
								view0.setFrame(frame0); 
							}
						};
						completion0 = new UIAnimationBlock.Completion() {
							@Override
							public void run(boolean finished) {
								frame0.origin.x = 0;
								view0.setFrame(frame0);
								view0.removeFromSuperview();
							}
						};
					} else {
						view0.removeFromSuperview();
					}
				}
				
				ctrl0.setNavigationController(null);
								
				final UIView view = ctrl.view();
				final CGRect frame = getViewControllerFrame();
				
				if (animated) {
					frame.origin.x = -frame.size.width;
					view.setFrame(frame); 
					view().addSubview(view);
					
					final UIAnimationBlock _anim0 = anim0;
					final UIAnimationBlock.Completion _completion0 = completion0;
					
					UIView.animateWithDurationAnimationsCompletion(0.3, new UIAnimationBlock() {
						@Override
						public void run() {
							if (_anim0 != null) {
								_anim0.run();
							}
							frame.origin.x = 0;
							view.setFrame(frame); 
						}
					}, new UIAnimationBlock.Completion() {
						@Override
						public void run(boolean finished) {
							if (_completion0 != null) {
								_completion0.run(finished);
							}
						}
					});
				} else {
					view.setFrame(frame); 
					view().addSubview(view);
				}
				
				if (!mToolbarHidden) {
					mToolbar.setItems(ctrl.toolbarItems());
				}
				
				NSMutableArray ctrls = new NSMutableArray(3);
				NSRange range = NSMakeRange(index + 1, count - index - 1);
				for (int i = 0; i < range.length; i++) { 
					UIViewController ctrl2 = (UIViewController) 
									mViewControllers.objectAtIndex(i + range.location);
					ctrl2.setNavigationController(null);
					ctrls.addObject(ctrl2); 
				}
				mViewControllers.removeObjectsInRange(range);
				
				return new NSArray(ctrls);
			}
		}
		
		return null;
	}
	
	public NSArray popToRootViewControllerAnimated(boolean animated) {
		UIViewController root = (UIViewController)mViewControllers.firstObject();
		if (root != null) {
			popToViewControllerAnimated(root, animated);
		}
		return null;
	}

	@Override
	public boolean navigationBarShouldPushItem(UINavigationBar navigationBar, UINavigationItem item) {
		return true;
	}

	@Override
	public void navigationBarDidPushItem(UINavigationBar navigationBar, UINavigationItem item) {

	}

	@Override
	public boolean navigationBarShouldPopItem(UINavigationBar navigationBar, UINavigationItem item) {
		popViewControllerAnimated(true);
		return false;
	}

	@Override
	public void navigationBarDidPopItem(UINavigationBar navigationBar, UINavigationItem item) {
		
	}
	
}
